/*
 * This file is part of "IdeWiki" project.
 *
 * Copyright (c) 2008 Hendrik Ebel
 * All Rights Reserved.
 *
 * Please visit http://code.google.com/p/idewiki for updates and contact.
 *
 * --LICENSE NOTICE--
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 3
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; If not, see <http://www.gnu.org/licenses/>.
 * --LICENSE NOTICE--
 */
package ws.ebel.idewiki.xmlrpc;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Date;
import java.util.Vector;

import org.apache.xmlrpc.DefaultXmlRpcTransport;
import org.apache.xmlrpc.XmlRpcClient;
import org.apache.xmlrpc.XmlRpcException;
import org.apache.xmlrpc.XmlRpcRequest;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;

import ws.ebel.idewiki.Activator;
import ws.ebel.idewiki.util.CommonHelper;

/**
 * The Class RpcClient.
 */
public class RpcClient implements IPropertyChangeListener {
    
    /** The server. */
    private String server;
    
    /** The username. */
    private String username;
    
    /** The password. */
    private String password;
    
    /** The client. */
    private XmlRpcClient client;
    
    /** The rpc client. */
    private static RpcClient rpcClient = null;
    
    /** The xml rpc transport. */
    private DefaultXmlRpcTransport xmlRpcTransport = null;
    
    /** The Constant API_PREFIX. */
    public static final String API_PREFIX = "idewiki.";

    /**
     * The Constructor.
     */
    private RpcClient() {
        setRpcConnectParameter();
        Activator.getDefault().getPreferenceStore().addPropertyChangeListener(this);
        try {
            client = new XmlRpcClient(server);
            xmlRpcTransport = new DefaultXmlRpcTransport(new URL(server));
            xmlRpcTransport.setBasicAuthentication(username, password);
        } catch (MalformedURLException e) {
            Activator.getDefault().reportError("XML RPC Error", "Please check the server url!");
        }

    }

    /**
     * Gets the instance.
     * 
     * @return the instance
     */
    public static synchronized RpcClient getInstance() {
        if (rpcClient == null) {
            rpcClient = new RpcClient();
        }

        return rpcClient;
    }

    /**
     * Execute.
     * 
     * @param args the args
     * @param method the method
     * 
     * @return the object
     * 
     * @throws IOException the IO exception
     * @throws XmlRpcException the xml rpc exception
     */
    private Object execute(String method, Vector args) throws XmlRpcException, IOException{
        return client.execute(new XmlRpcRequest(API_PREFIX + method, args), xmlRpcTransport);
    }

    /**
     * Get the snip content.
     * 
     * @param snipName the snip name
     * 
     * @return the snip name for ok or null
     */
    public SnipBean getSnipContent(String snipName) {
        SnipBean result = null; // error case
        Vector<String> params = new Vector<String>();
        params.addElement(CommonHelper.decode(snipName));

        try {
            String content = (String) execute("getSnip", params);
            String cUser = (String) execute("getSnipCreatorName", params);
            String mUser = (String) execute("getSnipModifierName", params);
            Date cTime = (Date) execute("getSnipCreatorTime", params);
            Date mTime = (Date) execute("getSnipModifierTime", params);
            
            result = new SnipBean(content, cUser, mUser, cTime, mTime, snipName);
            
        } catch (ClassCastException e){
            Activator.getDefault().logAndReport("ClassCastException", e.getMessage(), e);
        } catch (XmlRpcException e) {
            Activator.getDefault().logAndReport("XmlRpcException", e.getMessage(), e);
        } catch (IOException e) {
            Activator.getDefault().logAndReport("IOException", e.getMessage(), e);
        }
        
        return result;
    }
    
    /**
     * Update a snip with the given content.
     * 
     * @param aSnip the snip 
     * @return the snip name if update ok or null
     */
    public String updateSnip(SnipBean aSnip) {
        String result = null; // error case
        Vector<String> params = new Vector<String>();
        params.addElement(aSnip.getDecodeSnipName());
        params.addElement(aSnip.getContent());

        try {
            result = (String) execute("updateSnip", params);
        } catch (ClassCastException e){
            Activator.getDefault().logAndReport("ClassCastException", e.getMessage(), e);
        } catch (XmlRpcException e) {
            Activator.getDefault().logAndReport("XmlRpcException", e.getMessage(), e);
        } catch (IOException e) {
            Activator.getDefault().logAndReport("IOException", e.getMessage(), e);
        }
        
        return result;
    }
    
    /**
     * Update a snip with the given content.
     * 
     * @param aSnip the snip
     * @return the snip name if update ok or null
     */
    public String createSnip(SnipBean aSnip) {
        String result = null; // error case
        Vector<String> params = new Vector<String>();
        params.addElement(CommonHelper.decode(aSnip.getSnipName()));
        params.addElement(aSnip.getContent());

        try {
            result = (String) execute("createSnip", params);
        } catch (ClassCastException e){
            Activator.getDefault().logAndReport("ClassCastException", e.getMessage(), e);
        } catch (XmlRpcException e) {
            Activator.getDefault().logAndReport("XmlRpcException", e.getMessage(), e);
        } catch (IOException e) {
            Activator.getDefault().logAndReport("IOException", e.getMessage(), e);
        }
        
        return result;
    }

    /**
     * Sets the rpc connect parameter.
     */
    private void setRpcConnectParameter() {
        server = Activator.getDefault().getWikiUrlPreference() + "/RPC2";
        username = Activator.getDefault().getUserNamePreference();
        password = Activator.getDefault().getUserPasswordPreference();
    }
    
    /**
     * Property change.
     * 
     * @param event the event
     * 
     * @see org.eclipse.jface.util.IPropertyChangeListener#propertyChange(org.eclipse.jface.util.PropertyChangeEvent)
     */
    public void propertyChange(PropertyChangeEvent event) {
        setRpcConnectParameter();
        xmlRpcTransport.setBasicAuthentication(username, password);
    }
    
    /**
     * Dispose.
     */
    public void dispose(){
        Activator.getDefault().getPreferenceStore().removePropertyChangeListener(this);
    }
}